using System;
using AForge.Imaging;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using AForge.Imaging.Filters;
using System.Text;

namespace PBR.Filters
{
    class SegmentFilter : FilterGrayToColor
    {
        private static Color[] colorTable = new Color[]
        {
            Color.Red,		Color.Green,	Color.Blue,			Color.Yellow,
            Color.Violet,	Color.Brown,	Color.Olive,		Color.Cyan,

            Color.Magenta,	Color.Gold,		Color.Indigo,		Color.Ivory,
            Color.HotPink,	Color.DarkRed,	Color.DarkGreen,	Color.DarkBlue,

            Color.DarkSeaGreen,	Color.Gray,	Color.DarkKhaki,	Color.DarkGray,
            Color.LimeGreen, Color.Tomato,	Color.SteelBlue,	Color.SkyBlue,

            Color.Silver,	Color.Salmon,	Color.SaddleBrown,	Color.RosyBrown,
            Color.PowderBlue, Color.Plum,	Color.PapayaWhip,	Color.Orange
        };

        // blob counter
        private BlobCounter blobCounter = new BlobCounter();
        private Bitmap connectedComponentsImage;

        /// <summary>
        /// Stores the connected component data
        /// </summary>
        public BlobCounter BlobCounter
        {
            get { return blobCounter; }
            set { blobCounter = BlobCounter; }
        }

        /// <summary>
        /// A color image to visually represent the connected components
        /// </summary>
        public Bitmap ConnectedComponentsImage
        {
            get { return connectedComponentsImage; }
            set { connectedComponentsImage = value; }
        }

        /// <summary>
        /// Colors used to color the binary image.
        /// </summary>
        public static Color[] ColorTable
        {
            get { return colorTable; }
            set { colorTable = value; }
        }

        /// <summary>
        /// Specifies if blobs should be filtered.
        /// </summary>
        /// 
        /// <remarks><para>See documentation for <see cref="BlobCounterBase.FilterBlobs"/> property
        /// of <see cref="BlobCounterBase"/> class for more information.</para></remarks>
        /// 
        public bool FilterBlobs
        {
            get { return blobCounter.FilterBlobs; }
            set { blobCounter.FilterBlobs = value; }
        }

        /// <summary>
        /// Specifies if size filetering should be coupled or not.
        /// </summary>
        /// 
        /// <remarks><para>See documentation for <see cref="BlobCounterBase.CoupledSizeFiltering"/> property
        /// of <see cref="BlobCounterBase"/> class for more information.</para></remarks>
        /// 
        public bool CoupledSizeFiltering
        {
            get { return blobCounter.CoupledSizeFiltering; }
            set { blobCounter.CoupledSizeFiltering = value; }
        }

        /// <summary>
        /// Minimum allowed width of blob.
        /// </summary>
        /// 
        public int MinWidth
        {
            get { return blobCounter.MinWidth; }
            set { blobCounter.MinWidth = value; }
        }

        /// <summary>
        /// Minimum allowed height of blob.
        /// </summary>
        /// 
        public int MinHeight
        {
            get { return blobCounter.MinHeight; }
            set { blobCounter.MinHeight = value; }
        }

        /// <summary>
        /// Maximum allowed width of blob.
        /// </summary>
        /// 
        public int MaxWidth
        {
            get { return blobCounter.MaxWidth; }
            set { blobCounter.MaxWidth = value; }
        }

        /// <summary>
        /// Maximum allowed height of blob.
        /// </summary>
        /// 
        public int MaxHeight
        {
            get { return blobCounter.MaxHeight; }
            set { blobCounter.MaxHeight = value; }
        }

        /// <summary>
        /// Objects count.
        /// </summary>
        /// 
        /// <remarks>The amount of objects found in the last processed image.</remarks>
        /// 
        public int ObjectCount
        {
            get { return blobCounter.ObjectsCount; }
        }

        /// <summary>
        /// Process the filter on the specified image.
        /// </summary>
        /// 
        /// <param name="sourceData">Source image data.</param>
        /// <param name="destinationData">Destination image data.</param>
        /// 
        protected override unsafe void ProcessFilter(BitmapData sourceData, BitmapData destinationData)
        {
            // process the image
            blobCounter.ProcessImage(sourceData);

            // get object labels
            int[] labels = blobCounter.ObjectLabels;

            // get width and height
            int width = sourceData.Width;
            int height = sourceData.Height;

            int dstOffset = destinationData.Stride - width * 3;

            // do the job
            byte* dst = (byte*)destinationData.Scan0.ToPointer();
            int p = 0;

            // for each row
            for (int y = 0; y < height; y++)
            {
                // for each pixel
                for (int x = 0; x < width; x++, dst += 3, p++)
                {
                    if (labels[p] != 0)
                    {
                        Color c = colorTable[(labels[p] - 1) % colorTable.Length];

                        dst[RGB.R] = c.R;
                        dst[RGB.G] = c.G;
                        dst[RGB.B] = c.B;
                    }
                }
                dst += dstOffset;
            }
        }
    }
}
